package spring.cloud.tasks.api.controller;

import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import spring.cloud.tasks.api.domain.ExecutorInfo;
import spring.cloud.tasks.api.domain.TaskExecutorStatus12;
import spring.cloud.tasks.api.service.ExecutorService;
import spring.cloud.tasks.api.utils.Response;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * Executor overview related operations.
 */
@RequestMapping("/console/namespaces/{namespace:.+}/executors")
public class ExecutorOverviewController {

    private static final Logger log = LoggerFactory.getLogger(ExecutorOverviewController.class);

    private static final String TRAFFIC_OPERATION_EXTRACT = "extract";

    private static final String TRAFFIC_OPERATION_RECOVER = "recover";

    @Resource
    private ExecutorService executorService;

    /**
     * 获取域下所有executor基本信息
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
    @GetMapping
    public Response getExecutors(final HttpServletRequest request, @PathVariable String namespace,
                                 @RequestParam(required = false) String status) throws RuntimeException {
        if ("online".equalsIgnoreCase(status)) {
            return Response.success(executorService.getExecutorInfoList(namespace, TaskExecutorStatus12.ONLINE));
        }

        return Response.success(executorService.getExecutorInfoList(namespace));
    }

    /**
     * 获取executor被分配的作业分片信息
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
    @GetMapping(value = "/{executorName}/allocationWithStatus")
    public Response getExecutorAllocationWithStatus(final HttpServletRequest request,
                                                    @PathVariable String namespace, @PathVariable String executorName) throws RuntimeException {
        return Response.success(executorService.getExecutorAllocation(namespace, executorName));
    }

    /**
     * 获取executor运行中的作业分片信息
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
    @GetMapping(value = "/{executorName}/runningInfo")
    public Response getExecutorRunningInfo(final HttpServletRequest request,
                                           @PathVariable String namespace, @PathVariable String executorName) throws RuntimeException {
        return Response.success(executorService.getExecutorRunningInfo(namespace, executorName));
    }

    /**
     * 一键重排
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
    @PostMapping(value = "/shardAll")
    public Response shardAll(final HttpServletRequest request,
                             @PathVariable String namespace) throws RuntimeException {
        //assertIsPermitted(PermissionKeys.executorShardAllAtOnce, namespace);
        executorService.shardAll(namespace);
        return new Response();
    }

    /*
     * 摘流量与流量恢复
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})

    @PostMapping(value = "/{executorName}/traffic")
    public Response extractOrRecoverTraffic(final HttpServletRequest request,
                                            @PathVariable String namespace,
                                            @PathVariable String executorName,
                                            @RequestParam String operation) throws RuntimeException {
        //assertIsPermitted(PermissionKeys.executorExtractOrRecoverTraffic, namespace);
        extractOrRecoverTraffic(namespace, executorName, operation);
        return new Response();
    }

    /*
     * 批量摘流量与流量恢复
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})

    @PostMapping(value = "/traffic")
    public Response batchExtractOrRecoverTraffic(final HttpServletRequest request,
                                                 @PathVariable String namespace,
                                                 @RequestParam List<String> executorNames,
                                                 @RequestParam String operation) throws RuntimeException {
        //assertIsPermitted(PermissionKeys.executorBatchExtractOrRecoverTraffic, namespace);
        List<String> success2ExtractOrRecoverTrafficExecutors = Lists.newArrayList();
        List<String> fail2ExtractOrRecoverTrafficExecutors = Lists.newArrayList();
        for (String executorName : executorNames) {
            try {
                extractOrRecoverTraffic(namespace, executorName, operation);
                success2ExtractOrRecoverTrafficExecutors.add(executorName);
            } catch (Exception e) {
                log.warn("exception happens during extract or recover traffic of executor:" + executorName, e);
                fail2ExtractOrRecoverTrafficExecutors.add(executorName);
            }
        }

        if (!fail2ExtractOrRecoverTrafficExecutors.isEmpty()) {
            StringBuilder message = new StringBuilder();
            message.append("操作成功的executor:").append(success2ExtractOrRecoverTrafficExecutors).append("，")
                    .append("操作失败的executor:").append(fail2ExtractOrRecoverTrafficExecutors);
            throw new RuntimeException(message.toString());
        }

        return new Response();
    }

    private void extractOrRecoverTraffic(String namespace, String executorName, String operation)
            throws RuntimeException {
        if (TRAFFIC_OPERATION_EXTRACT.equals(operation)) {
            executorService.extractTraffic(namespace, executorName);
        } else if (TRAFFIC_OPERATION_RECOVER.equals(operation)) {
            executorService.recoverTraffic(namespace, executorName);
        } else {
            throw new RuntimeException("operation " + operation + "不支持");
        }
    }

    /**
     * 移除executor
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
    @DeleteMapping(value = "/{executorName}")
    public Response removeExecutor(final HttpServletRequest request,
                                   @PathVariable String namespace,
                                   @PathVariable String executorName) throws RuntimeException {
        //assertIsPermitted(PermissionKeys.executorRemove, namespace);
        // check executor is existed and online.
        checkExecutorStatus(namespace, executorName, TaskExecutorStatus12.OFFLINE, "Executor在线，不能移除");
        executorService.removeExecutor(namespace, executorName);
        return new Response();
    }

    /**
     * 批量移除executor
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
    @DeleteMapping
    public Response batchRemoveExecutors(final HttpServletRequest request,
                                         @PathVariable String namespace,
                                         @RequestParam List<String> executorNames) throws RuntimeException {
        //assertIsPermitted(PermissionKeys.executorBatchRemove, namespace);
        // check executor is existed and online.
        List<String> success2RemoveExecutors = Lists.newArrayList();
        List<String> fail2RemoveExecutors = Lists.newArrayList();
        for (String executorName : executorNames) {
            try {
                checkExecutorStatus(namespace, executorName, TaskExecutorStatus12.OFFLINE, "Executor在线，不能移除");
                executorService.removeExecutor(namespace, executorName);
                success2RemoveExecutors.add(executorName);
            } catch (Exception e) {
                log.warn("exception happens during remove executor:" + executorName, e);
                fail2RemoveExecutors.add(executorName);
            }
        }
        if (!fail2RemoveExecutors.isEmpty()) {
            StringBuilder message = new StringBuilder();
            message.append("删除成功的executor:").append(success2RemoveExecutors).append("，").append("删除失败的executor:")
                    .append(fail2RemoveExecutors);
            throw new RuntimeException(message.toString());
        }

        return new Response();
    }

    private void checkExecutorStatus(String namespace, String executorName, TaskExecutorStatus12 status, String errMsg)
            throws RuntimeException {
        ExecutorInfo executorInfo = executorService.getExecutorInfo(namespace, executorName);
        if (executorInfo == null) {
            throw new RuntimeException("Executor不存在");
        }
        if (status != executorInfo.getStatus()) {
            throw new RuntimeException(errMsg);
        }
    }


    /**
     * 一键重启。
     */
    //@ApiResponses(value = {@ApiResponse(code = 200, message = "Success/Fail", response = RequestResult.class)})
    @PostMapping(value = "/{executorName}/restart")
    public Response restart(final HttpServletRequest request,
                            @PathVariable String namespace,
                            @PathVariable String executorName) throws RuntimeException {
        //assertIsPermitted(PermissionKeys.executorRestart, namespace);
        // check executor is existed and online.
        checkExecutorStatus(namespace, executorName, TaskExecutorStatus12.ONLINE, "Executor必须在线才可以重启");
        executorService.restart(namespace, executorName);
        return new Response();
    }
}
